package com.dkts.oil.test.road;

import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.linearref.LengthIndexedLine;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.FileReader;
import java.io.FileWriter;
import java.util.*;

public class ShippingRouteGenerator1 {

    public static void main(String[] args) throws Exception {
        FeatureJSON fjson = new FeatureJSON();

        // 1. 读取中心线，合并成单条 LineString
        FeatureIterator<SimpleFeature> lineIt = fjson.readFeatureCollection(new FileReader("src/main/resources/长江.geojson")).features();
        Geometry centerGeom = null;
        if (lineIt.hasNext()) {
            centerGeom = (Geometry) lineIt.next().getDefaultGeometry();
        }
        lineIt.close();

        GeometryFactory gf = new GeometryFactory();
        LineString centerLine;

        if (centerGeom == null) {
            throw new IllegalArgumentException("中心线数据为空");
        } else if (centerGeom instanceof MultiLineString) {
            MultiLineString mls = (MultiLineString) centerGeom;
            List<Coordinate> coords = new ArrayList<>();
            for (int i = 0; i < mls.getNumGeometries(); i++) {
                LineString ls = (LineString) mls.getGeometryN(i);
                Coordinate[] lsCoords = ls.getCoordinates();
                // 合并时避免重复点
                if (!coords.isEmpty() && coords.get(coords.size() - 1).equals2D(lsCoords[0])) {
                    for (int j = 1; j < lsCoords.length; j++) coords.add(lsCoords[j]);
                } else {
                    Collections.addAll(coords, lsCoords);
                }
            }
            centerLine = gf.createLineString(coords.toArray(new Coordinate[0]));
        } else if (centerGeom instanceof LineString) {
            centerLine = (LineString) centerGeom;
        } else {
            throw new IllegalArgumentException("中心线不是 LineString 或 MultiLineString 类型");
        }

        // 2. 读取港口点
        FeatureIterator<SimpleFeature> portIt = fjson.readFeatureCollection(new FileReader("src/main/resources/长江港口.geojson")).features();

        LengthIndexedLine indexedLine = new LengthIndexedLine(centerLine);

        // 3. 存放所有垂足点索引和坐标，用于插入航线坐标中
        TreeMap<Double, Coordinate> insertPoints = new TreeMap<>();

        // 4. 存放港口点到垂足点的连线
        List<LineString> portToLineLinks = new ArrayList<>();

        while (portIt.hasNext()) {
            SimpleFeature feature = portIt.next();
            Point portPt = (Point) feature.getDefaultGeometry();

            // 计算投影索引（垂足点位置）
            double index = indexedLine.project(portPt.getCoordinate());

            // 得到垂足点坐标（一定在线上）
            Coordinate projCoord = indexedLine.extractPoint(index);

            // 插入点索引唯一，若有重复可考虑微调索引避免覆盖
            if (insertPoints.containsKey(index)) {
                // 细微偏移索引避免覆盖
                index += 1e-10;
            }
            insertPoints.put(index, projCoord);

            // 生成港口点到垂足点的连线
            Coordinate[] linkCoords = new Coordinate[]{portPt.getCoordinate(), projCoord};
            LineString linkLine = gf.createLineString(linkCoords);
            portToLineLinks.add(linkLine);
        }
        portIt.close();

        // 5. 插入垂足点到中心线坐标序列中，生成新的折线
        Coordinate[] originalCoords = centerLine.getCoordinates();
        List<Coordinate> newCoords = new ArrayList<>();

        Iterator<Map.Entry<Double, Coordinate>> insertIt = insertPoints.entrySet().iterator();
        Map.Entry<Double, Coordinate> currentInsert = insertIt.hasNext() ? insertIt.next() : null;

        for (int i = 0; i < originalCoords.length - 1; i++) {
            Coordinate c1 = originalCoords[i];
            Coordinate c2 = originalCoords[i + 1];
            newCoords.add(c1);

            double startIndex = indexedLine.project(c1);
            double endIndex = indexedLine.project(c2);

            // 插入所有垂足点，保证点在对应线段内部且按顺序插入
            while (currentInsert != null && currentInsert.getKey() > startIndex && currentInsert.getKey() < endIndex) {
                newCoords.add(currentInsert.getValue());
                currentInsert = insertIt.hasNext() ? insertIt.next() : null;
            }
        }
        newCoords.add(originalCoords[originalCoords.length - 1]);

        LineString newRouteLine = gf.createLineString(newCoords.toArray(new Coordinate[0]));

        // 6. 连贯性检查示例（可选）
        for (int i = 0; i < newCoords.size() - 1; i++) {
            double dist = newCoords.get(i).distance(newCoords.get(i + 1));
            //System.out.println("Segment " + i + " length: " + dist);
            // 如果需要可根据距离做断点检测
        }

        // 7. 输出主航线和港口连线（垂线）

        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.setName("ShippingRouteWithLinks");
        typeBuilder.add("geometry", LineString.class);
        SimpleFeatureType TYPE = typeBuilder.buildFeatureType();

        ListFeatureCollection featureCollection = new ListFeatureCollection(TYPE);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        // 主航线 Feature
        featureBuilder.add(newRouteLine);
        featureCollection.add(featureBuilder.buildFeature(null));

        // 港口连线 Features
        for (LineString linkLine : portToLineLinks) {
            featureBuilder.add(linkLine);
            featureCollection.add(featureBuilder.buildFeature(null));
        }

        try (FileWriter writer = new FileWriter("src/main/resources/shipping_route_with_links.geojson")) {
            fjson.writeFeatureCollection(featureCollection, writer);
        }

        System.out.println("✔ 航线和港口连线生成完成，结果保存在 shipping_route_with_links.geojson");
    }
}
